/*
 *  Copyright (c) 2011 Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany.
 *  All rights reserved. This program and the accompanying materials
 *  are made available under the terms of the GNU Lesser Public License v2.1
 *  which accompanies this distribution, and is available at
 *  http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 *
 *  Contributors:
 *      Leibniz Institute of Plant Genetics and Crop Plant Research (IPK), Gatersleben, Germany - initial API and implementation
 */
package de.ipk_gatersleben.bit.bi.edal.primary_data.file;

import java.security.Principal;
import java.util.List;
import java.util.UUID;

import javax.mail.internet.InternetAddress;
import javax.security.auth.Subject;

import org.apache.log4j.Logger;

import de.ipk_gatersleben.bit.bi.edal.primary_data.EdalConfiguration;
import de.ipk_gatersleben.bit.bi.edal.primary_data.metadata.MetaData;
import de.ipk_gatersleben.bit.bi.edal.primary_data.reference.ApprovalServiceProvider;
import de.ipk_gatersleben.bit.bi.edal.primary_data.reference.PersistentIdentifier;
import de.ipk_gatersleben.bit.bi.edal.primary_data.security.PermissionProvider;

/**
 * Interface that provide all necessary classes of a eDAL implementations.
 * 
 * @author lange
 * @author arendd
 */
public interface ImplementationProvider {

	/**
	 * Create an new instance of the {@link MetaData} implementation class.
	 * 
	 * @return a instance of the implementing class of {@link MetaData}.
	 */
	MetaData createMetaDataInstance();

	/**
	 * Getter for the available space in the mount path of eDAL.
	 * 
	 * @return available space
	 * @throws EdalException
	 *             if no path is specified.
	 */
	Long getAvailableStorageSpace() throws EdalException;

	/**
	 * Getter for the current logger for system output
	 * 
	 * @return Logger
	 */
	Logger getLogger();

	/**
	 * Getter for the {@link PermissionProvider} implementation class.
	 * 
	 * @return the instance of {@link PermissionProvider} to be use.
	 */
	Class<? extends PermissionProvider> getPermissionProvider();

	/**
	 * Getter for the {@link PrimaryDataDirectory} implementation class.
	 * 
	 * @return the implementing class of {@link PrimaryDataDirectory}.
	 */
	Class<? extends PrimaryDataDirectory> getPrimaryDataDirectoryProvider();

	/**
	 * Getter to load a {@link PrimaryDataEntity} object specified by
	 * {@link UUID} and number of the {@link PrimaryDataEntityVersion}.
	 * 
	 * @param uuid
	 *            the {@link UUID} of the {@link PrimaryDataEntity}.
	 * @param versionNumber
	 *            the version number of the {@link PrimaryDataEntityVersion}.
	 * @throws EdalException
	 *             if there is no {@link PrimaryDataEntity} with the specified
	 *             values.
	 * @return the specified {@link PrimaryDataEntity}
	 */
	PrimaryDataEntity getPrimaryDataEntityByID(String uuid, long versionNumber)
			throws EdalException;

	/**
	 * Getter for the {@link PrimaryDataFile} implementation class.
	 * 
	 * @return the implementing class of {@link PrimaryDataFile}.
	 */
	Class<? extends PrimaryDataFile> getPrimaryDataFileProvider();

	/**
	 * Getter all supported {@link Principal}s of the current eDAL system.
	 * 
	 * @return the list of supported {@link Principal}s
	 * @throws EdalException
	 *             if unable to load {@link Principal}s.
	 */
	List<Class<? extends Principal>> getSupportedPrincipals()
			throws EdalException;

	/**
	 * Getter for the used space in the mount path of eDAL.
	 * 
	 * @return used space
	 * @throws EdalException
	 *             if no path is specified.
	 */
	Long getUsedStorageSpace() throws EdalException;

	/**
	 * Check if a root {@link PrimaryDataDirectory} exists and return it or
	 * create an new root {@link PrimaryDataDirectory}
	 * 
	 * @return the root {@link PrimaryDataDirectory}.
	 * @throws PrimaryDataDirectoryException
	 *             if unable to mount with the eDAL system.
	 */
	PrimaryDataDirectory mount(
			List<Class<? extends Principal>> supportedPrincipals)
			throws PrimaryDataDirectoryException;

	/**
	 * Cleanup all resources used by the particular implementation provider
	 */
	void shutdown();

	/**
	 * Getter for the {@link ApprovalServiceProvider} implementation class
	 * 
	 * @return the implementing class of {@link ApprovalServiceProvider}
	 */
	Class<? extends ApprovalServiceProvider> getApprovalServiceProvider();

	/**
	 * Getter for the configuration class with all parameter to start the eDAL
	 * system.
	 * 
	 * @return an {@link EdalConfiguration} class.
	 */
	EdalConfiguration getConfiguration();

	/**
	 * Getter for a {@link PrimaryDataEntity} for a reviewer to create a
	 * temporary landing page.
	 * 
	 * @param uuid
	 *            the id of the {@link PrimaryDataEntity}
	 * @param versionNumber
	 *            the number of the {@link PrimaryDataEntityVersion}
	 * @param internalId
	 *            the internal ID of the corresponding {@link PublicReference}
	 * @param reviewerCode
	 *            the id to identify a reviewer
	 * @return the searched {@link PrimaryDataEntity}
	 * @throws EdalException
	 *             if unable to load the {@link PrimaryDataEntity}
	 */
	PrimaryDataEntity getPrimaryDataEntityForReviewer(String uuid,
			long versionNumber, String internalId, int reviewerCode)
			throws EdalException;

	/**
	 * Load the email address of the existing root user.
	 * 
	 * @return the email address.
	 * @throws EdalException
	 *             If unable to load existing root user.
	 */
	InternetAddress getPreviousRootUser() throws EdalException;

	InternetAddress getRootUser();

	void storeRootUser(Subject subject, InternetAddress address, UUID uuid)
			throws EdalException;

	boolean isRootValidated(InternetAddress address);

	boolean validateRootUser(InternetAddress address, UUID uuid);

	PrimaryDataEntity getPrimaryDataEntityForPersistenIdentifier(String uuid,
			long versionNumber, PersistentIdentifier persistentIdentifier)
			throws EdalException;

	PrimaryDataEntity reloadPrimaryDataEntityByID(String uuid,
			long versionNumber) throws EdalException;

}